﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using BlogLite.Models.Database;
using BlogLite.Areas.Admin.Models;
using Ninject;
using BlogLite.Models;
using BlogLite.Areas.Admin.Helpers;
using BlogLite.Helpers;

namespace BlogLite.Areas.Admin.Controllers
{
    [HandleErrorWithElmah]
    public class PostController : Controller
    {
        [Inject]
        public IBlogLiteRepository Repository { get; set; }

        //
        // GET: /Admin/Post/

        [HttpGet, Authorize]
        public ActionResult Index()
        {
            return View();
        }

        //
        // GET: /Admin/Post/Create

        [HttpGet, Authorize]
        public ActionResult Create()
        {
            PostViewModel viewModel = new PostViewModel();
            viewModel.Post = new Post();
            viewModel.SelectedTags = new List<string>();
            viewModel.Tags = new MultiSelectList(Repository.Tags, "TagId", "TagName", viewModel.SelectedTags);

            return View(viewModel);
        }

        //
        // POST: /Admin/Post/Create

        [HttpPost, Authorize, ValidateAntiForgeryToken]
        public ActionResult Create(Post post, List<string> selectedTags, string newTags)
        {
            // For whatever reason, the DefaultModelBinder will not bind to PostViewModel
            // (all values end up being null), so we can get all the pertinent info from the method 
            // variables or we can write a custom model binder (which we might want to do if we have 
            // the same problem on Edit).

            if (ModelState.IsValid)
            {
                // Add new tags to database
                post.Tags = new List<Tag>();

                if (!string.IsNullOrWhiteSpace(newTags))
                {
                    var tags = Repository.Tags;

                    // Check each tag to make sure it doesnt exist already
                    foreach (var splitTag in newTags.Split(','))
                    {
                        string trimmedTag = splitTag.Trim();
                        var existingTag = tags.Where(t => t.TagName == trimmedTag).SingleOrDefault();

                        if (existingTag != null)
                            post.Tags.Add(existingTag); // Add the existing tag to the post
                        else
                            post.Tags.Add(new Tag() { TagName = trimmedTag }); // Add a new tag to the post
                    }
                }

                // Get the tags and associate them with the post 
                if (selectedTags != null)
                    foreach (var tag in selectedTags)
                        post.Tags.Add((Repository.GetTagByTagId(Convert.ToInt32(tag))));
               
                // Set the last modified date
                post.LastModified = DateTime.Now;

                // Associate the user with the post
                post.User = Repository.GetUserByUsername(User.Identity.Name);

                // Save the post
                Repository.AddPost(post);
                Repository.Save();

                // Redirect to index
                return RedirectToAction("Index");
            }

            // Something was missed by the client side validation, so recreate the multiselect list
            // and send it back to the view.
            PostViewModel viewModel = new PostViewModel();
            viewModel.Post = post;
            viewModel.SelectedTags = new List<string>();
            viewModel.Tags = new MultiSelectList(Repository.Tags, "TagId", "TagName", viewModel.SelectedTags);

            return View(viewModel);
        }

        //
        // GET: /Admin/Post/Edit

        [HttpGet, Authorize]
        public ActionResult Edit(int id)
        {
            var post = Repository.GetPostByPostId(id);

            if (post == null)
                return RedirectToRoute("Admin_Error404");

            // Get all the tags associated with the post so they are 
            // selected in the multiselect listbox
            List<string> tags = new List<string>();

            foreach (var tag in post.Tags)
                tags.Add(tag.TagId.ToString());

            PostViewModel viewModel = new PostViewModel();
            viewModel.Post = post;
            viewModel.SelectedTags = tags;
            viewModel.Tags = new MultiSelectList(Repository.Tags, "TagId", "TagName", viewModel.SelectedTags);          

            return View(viewModel);
        }

        //
        // POST: /Admin/Post/Edit

        [HttpPost, Authorize, ValidateAntiForgeryToken]
        public ActionResult Edit(Post post, List<string> selectedTags, string newTags)
        {
            if (ModelState.IsValid)
            {
                var updatedPost = Repository.GetPostByPostId(post.PostId);

                // Update the post
                if (TryUpdateModel<Post>(updatedPost, "Post"))
                {
                    // Add new tags to database
                    updatedPost.Tags = new List<Tag>();

                    if (!string.IsNullOrWhiteSpace(newTags))
                    {
                        var tags = Repository.Tags;

                        // Check each tag to make sure it doesnt exist already
                        foreach (var splitTag in newTags.Split(','))
                        {
                            string trimmedTag = splitTag.Trim();
                            var existingTag = tags.Where(t => t.TagName == trimmedTag).SingleOrDefault();

                            if (existingTag != null)
                                updatedPost.Tags.Add(existingTag); // Add the existing tag to the post
                            else
                                updatedPost.Tags.Add(new Tag() { TagName = trimmedTag }); // Add a new tag to the post
                        }
                    }

                    // Get the tags and associate them with the post
                    if (selectedTags != null)
                        foreach (var tag in selectedTags)
                            updatedPost.Tags.Add((Repository.GetTagByTagId(Convert.ToInt32(tag))));

                    // Set the last modified date
                    updatedPost.LastModified = DateTime.Now;

                    // Save the post
                    Repository.Save();

                    // Redirect to index
                    return RedirectToAction("Index");
                }
            }

            // Something was missed by the client side validation, so recreate the multiselect list
            // and send it back to the view.
            PostViewModel viewModel = new PostViewModel();
            viewModel.Post = post;
            viewModel.SelectedTags = new List<string>();
            viewModel.Tags = new MultiSelectList(Repository.Tags, "TagId", "TagName", viewModel.SelectedTags);

            return View(viewModel);
        }

        //
        // AJAX: /Admin/Post/GetPosts

        [HttpGet, Authorize]
        public JsonResult GetPosts(string sidx, string sord, int page, int rows)
        {
            var posts = Repository.Posts;

            // Sort posts
            switch (sidx)
            {
                case "Title": 
                    if (sord == "asc")
                        posts = posts.OrderBy(p => p.Subject);
                    else
                        posts = posts.OrderByDescending(p => p.Subject);
                    break;
                case "PostDate": 
                    if (sord == "asc")
                        posts = posts.OrderBy(p => p.PostDate);
                    else
                        posts = posts.OrderByDescending(p => p.PostDate);
                    break;
                case "LastModified": 
                    if (sord == "asc")
                        posts = posts.OrderBy(p => p.LastModified);
                    else
                        posts = posts.OrderByDescending(p => p.LastModified);
                    break;
            }

            // Determine paging information for jqGrid
            int pageIndex = page - 1;
            int totalRecords = posts.Count();
            int totalPages = (int)Math.Ceiling((float)totalRecords / (float)rows);

            posts = posts.Skip(pageIndex * rows).Take(rows).ToList();

            // Build JSON Result
            JQGridData gridData = new JQGridData()
            {
                total = totalPages,
                page = page,
                records = totalRecords,
            };

            List<JQGridRow> gridRows = new List<JQGridRow>();

            foreach (var post in posts)
                gridRows.Add(new JQGridRow() { i = post.PostId.ToString(), cell = new List<string>() { "<a href='/Admin/Post/Edit/" + post.PostId + "'>" + post.Subject + "</a>", post.PostDate.ToShortDateString(), post.LastModified.ToShortDateString() } });

            gridData.rows = gridRows;

            return Json(gridData, JsonRequestBehavior.AllowGet);
        }
    }
}
